package edu.hawaii.jmotif.sequitur.view;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;

import javax.swing.JPanel;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.entity.ChartEntity;
import org.jfree.chart.entity.XYItemEntity;
import org.jfree.chart.event.ChartProgressEvent;
import org.jfree.chart.event.ChartProgressListener;
import org.jfree.chart.plot.IntervalMarker;
import org.jfree.chart.plot.ValueMarker;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.Layer;
import org.jfree.ui.LengthAdjustmentType;
import org.jfree.ui.RectangleAnchor;
import org.jfree.ui.TextAnchor;

import edu.hawaii.jmotif.sequitur.logic.MotifChartData;
import edu.hawaii.jmotif.sequitur.logic.SAXPosition;
import edu.hawaii.jmotif.sequitur.logic.SAXString;
import edu.hawaii.jmotif.sequitur.model.SequiturMessage;

/**
 * 
 * handling the chart panel and sequitur rules table
 * 
 * @author Manfred Lerner
 * 
 */
public class SequiturChartPanel extends JPanel implements PropertyChangeListener, ChartProgressListener
 {

  /** Fancy serial. */
  private static final long serialVersionUID = -2710973854572981568L;

  /** The chart container. */
  private JFreeChart chart;

  /** The plot itself. */
  private XYPlot plot;

  /** Current chart data instance. */
  private MotifChartData chartData;

  /** JFreeChart Object holding the chart times eries */
  XYSeriesCollection chartXYSeriesCollection;
  
  /** Position of the previous mouse click in the chart */
  double previousClickPosition = 0;
  
  /**
   * Constructor.
   */
  public SequiturChartPanel() {
    super();
  }

  /**
   * Constructor.
   * 
   * @param chartData the chart data.
   */
  public SequiturChartPanel(MotifChartData chartData) {
    if (chartData != null) {
      this.chartData = chartData;
      
      resetChartPanel();
    }
  }

  /**
   * This sets the chartData and forces the panel to repaint itself showing the new chart.
   * 
   * @param chartData the data to use.
   */
  public void set(MotifChartData chartData) {
    this.chartData = chartData;
    resetChartPanel();
  }

  /**
   * Get the chart.
   * 
   * @return JFreeChart object
   */
  public JFreeChart getChart() {
    return chart;
  }

  /**
   * Creates the chart panel, puts it on display.
   * 
   */
  private void resetChartPanel() {

    // this is the new "insert" - elastic boundaries chart panel
    //
    paintTheChart();
    ChartPanel chartPanel = new ChartPanel(this.chart);
    chartPanel.setMinimumDrawWidth(0);
    chartPanel.setMinimumDrawHeight(0);
    chartPanel.setMaximumDrawWidth(1920);
    chartPanel.setMaximumDrawHeight(1200);
    
    
    // cleanup all the content
    //
    this.removeAll();

    // put the chart on show
    //
    this.add(chartPanel);

    // not sure if I need this
    //
    validate();
    repaint();
  }

  /**
   * highlight the original time series sequences of a rule
   * 
   * @param index index of the rule in the sequitur table
   */
  private void highlightPatternInChart(String rule) {

    System.out.println("Selected rule: " + rule);

    SAXString sax = new SAXString(chartData.getFreqData(), " ");

    String textRule = chartData.convert2OriginalSAXAlphabet('1', rule);
    System.out.println("text rule: " + textRule);
    ArrayList<SAXPosition> arrPos = sax.getRulePositions(chartData.getSAXWindowSize(),
        chartData.getSAXPaaSize(), textRule);
    System.out.println("Size: " + arrPos.size() + " - Positions: " + arrPos);
    plot.clearDomainMarkers();

    for (SAXPosition saxPos : arrPos) {
      addMarker(plot, saxPos.getStartPos(), saxPos.getEndPos());
    }
  }



  /**
   * @param plot plot for the marker
   * @param startVal start postion
   * @param endVal end position
   */
  void addMarker(XYPlot plot, int startVal, int endVal) {

    IntervalMarker marker = new IntervalMarker(startVal, endVal);
    marker.setLabelOffsetType(LengthAdjustmentType.EXPAND);
    marker.setPaint(new Color(134, 254, 225));
    marker.setAlpha((float) 0.60);
    marker.setLabelFont(new Font("SansSerif", Font.PLAIN, 12));
    marker.setLabelPaint(Color.green);
    marker.setLabelAnchor(RectangleAnchor.TOP_LEFT);
    marker.setLabelTextAnchor(TextAnchor.TOP_LEFT);

    plot.addDomainMarker(marker, Layer.BACKGROUND);

    ValueMarker markStart = new ValueMarker(startVal, new Color(31, 254, 225),
        new BasicStroke(2.0f));
    ValueMarker markEnd = new ValueMarker(endVal, new Color(31, 254, 225), new BasicStroke(2.0f));
    plot.addDomainMarker(markStart, Layer.BACKGROUND);
    plot.addDomainMarker(markEnd, Layer.BACKGROUND);
  }

  /**
   * create the chart for the original time series
   * 
   * @return a JFreeChart object of the chart
   */
  private void paintTheChart() {

    // making the data
    //
    XYSeries dataset = new XYSeries("Series");
    int size = chartData.getOriginalTimeseries().size();
    double dValues[] = chartData.getOriginalTimeseries().values();
    for (int i = 0; i < size; i++) {
      dataset.add(i, (float)dValues[i]);
    }
    chartXYSeriesCollection = new XYSeriesCollection(dataset);
    
    // set the renderer
    //
    XYLineAndShapeRenderer xyRenderer = new XYLineAndShapeRenderer(true, false);
    xyRenderer.setSeriesPaint(0, new Color(0, 0, 0));
    xyRenderer.setBaseStroke(new BasicStroke(3));

    // X - the time axis
    //
    NumberAxis timeAxis = new NumberAxis();
    timeAxis.setLabel("Time");

    // Y axis
    //
    NumberAxis valueAxis = new NumberAxis("Values");
    valueAxis.setAutoRangeIncludesZero(false);
    valueAxis.setLabel("Values");

    // put these into collection of dots
    //
    this.plot = new XYPlot(chartXYSeriesCollection, timeAxis, valueAxis, xyRenderer);

    
    
    // finally, create the chart
    this.chart = new JFreeChart("", JFreeChart.DEFAULT_TITLE_FONT, plot, false);

    // set the progress listener to react to mouse clicks in the chart
    this.chart.addProgressListener(this);
  }
  

  
  public void chartProgress(ChartProgressEvent chartprogressevent)
  {
    if (chartprogressevent.getType() != 2) return;

	XYPlot xyplot = (XYPlot)chart.getPlot();
	
	double pos = xyplot.getDomainCrosshairValue();
	
	// this is needed because the call of highlightPatternInChart triggers a ChartProgessEvent
	if(previousClickPosition == pos) return;
	
	SAXString sax = new SAXString(chartData.getFreqData(), " ");
	String rule = sax.getRuleFromPosition(chartData, (int)pos);
	if(rule != null) {
		firePropertyChange(SequiturMessage.MAIN_CHART_CLICKED_MESSAGE, "", rule);
		System.out.println("Clicked Property Change fired with rule: " + rule);
	}
		
	previousClickPosition = pos;
  }


  @Override
  public void propertyChange(PropertyChangeEvent evt) {
    if (SequiturRulesPanel.FIRING_PROPERTY.equalsIgnoreCase(evt.getPropertyName())) {
      String newlySelectedRaw = (String) evt.getNewValue();
      highlightPatternInChart(newlySelectedRaw);
    }
  }

}
